package io.gitee.terralian.code.generator.service.template.impl;

import io.gitee.terralian.code.generator.service.template.TemplateEngine;
import io.gitee.terralian.code.generator.service.template.entity.GenerateConfig;
import cn.hutool.core.util.StrUtil;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.context.Context;
import org.apache.velocity.runtime.RuntimeInstance;
import org.apache.velocity.tools.ToolManager;
import org.apache.velocity.tools.config.EasyFactoryConfiguration;
import org.apache.velocity.tools.generic.CollectionTool;
import org.apache.velocity.tools.generic.ComparisonDateTool;
import org.apache.velocity.tools.generic.DisplayTool;
import org.apache.velocity.tools.generic.EscapeTool;
import org.apache.velocity.tools.generic.JsonTool;
import org.apache.velocity.tools.generic.LinkTool;
import org.apache.velocity.tools.generic.LoopTool;
import org.apache.velocity.tools.generic.MathTool;
import org.apache.velocity.tools.generic.NumberTool;
import org.apache.velocity.tools.generic.XmlTool;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;

@Service
public class VelocityTemplateEngine implements TemplateEngine {

    private final RuntimeInstance runtimeInstance;
    private final ToolManager toolManager;

    public VelocityTemplateEngine() {
        runtimeInstance = new RuntimeInstance();
        runtimeInstance.init();

        toolManager = new ToolManager();
        EasyFactoryConfiguration config = new EasyFactoryConfiguration();
        config.toolbox("application")
                .tool(ComparisonDateTool.class)
                .tool(MathTool.class)
                .tool(NumberTool.class)
                .tool(DisplayTool.class)
                .tool(EscapeTool.class)
                .tool(CollectionTool.class)
                .tool(XmlTool.class)
                .tool(JsonTool.class);
        config.toolbox("request")
                .tool(LinkTool.class)
                .tool(LoopTool.class);
        toolManager.configure(config);
    }

    @Override
    public void parse(GenerateConfig config, String templateData, Writer writer) {
        Context context = new VelocityContext(config.getVariables(), toolManager.createContext());
        Template template = new Template();
        template.setEncoding(StandardCharsets.UTF_8.name());
        template.setRuntimeServices(runtimeInstance);
        try (BufferedReader br = new BufferedReader(new StringReader(StrUtil.emptyToDefault(templateData, "")))) {
            Object data = runtimeInstance.parse(br, template);
            template.setData(data);
            template.initDocument();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        template.merge(context, writer);
    }

    @Override
    public String parse(GenerateConfig config, String templateData) {
        StringWriter stringWriter = new StringWriter();
        parse(config, templateData, stringWriter);
        return stringWriter.toString();
    }
}
